package com.ferry.common.util.concurrent.rejected;

import com.ferry.common.util.JvmUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by daiyong
 */
public abstract class AbstractRejectedExecutionHandler implements RejectedExecutionHandler {

	private static final Logger logger = LoggerFactory.getLogger(AbstractRejectedExecutionHandler.class);

	private final String threadPoolName;
	private final AtomicBoolean dumpNeeded;
	private final String dumpPrefixName;

	public AbstractRejectedExecutionHandler(String threadPoolName, boolean dumpNeeded, String dumpPrefixName) {
		this.threadPoolName = threadPoolName;
		this.dumpNeeded = new AtomicBoolean(dumpNeeded);
		this.dumpPrefixName = dumpPrefixName;
	}

	public void dumpJvmInfoIfNeeded() {
		if (dumpNeeded.getAndSet(false)) {
			String now = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
			String name = threadPoolName + "_" + now;
			try (FileOutputStream fileOutput = new FileOutputStream(new File(dumpPrefixName + "_dump_" + name + ".log"))) {

				List<String> stacks = JvmUtil.jStack();
				for (String s : stacks) {
					fileOutput.write(s.getBytes(StandardCharsets.UTF_8));
				}

				List<String> memoryUsages = JvmUtil.memoryUsage();
				for (String m : memoryUsages) {
					fileOutput.write(m.getBytes(StandardCharsets.UTF_8));
				}

				if (JvmUtil.memoryUsed() > 0.9) {
					JvmUtil.jMap(dumpPrefixName + "_dump_" + name + ".hprof", false);
				}
			} catch (Throwable t) {
				logger.error("Dump jvm info error: {}.", t);
			}
		}
	}
}
